﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using kk.components.contracts;
using kk.messages.contracts.DataModel;
using LoungeRepo.Contracts.Core;
using LoungeRepo.Contracts.EntityStore;
using LoungeRepo.Core;

namespace kk.belegungsadapter
{
    public class BelegungsAdapter : IBelegungsAdapter
    {
        private readonly ILoungeRepository repo;


        public BelegungsAdapter() : this("Belegungen") { }
        internal BelegungsAdapter(string repoPath) { this.repo = new LoungeRepository(repoPath); }
        internal BelegungsAdapter(ILoungeRepository repo) { this.repo = repo; }


        public void ProcessBelegungenZuVorstellung(Request<Vorstellung, IEnumerable<Platzposition>> request)
        {
            request.ResponsePin(Finde_Belegungen_zu_Vorstellung(
                                    request.RequestData.Termin, 
                                    request.RequestData.Saal)
                                .Select(belegung => belegung.Platz));
        }


        public void ProcessReservierungsanfrage(Request<Reservierungsanfrage, Reservierungsbestätigung> request)
        {
            var belegungen = Finde_Belegungen_zu_Vorstellung(request.RequestData.Vorstellung.Termin, request.RequestData.Vorstellung.Saal);
            if (Sind_Reservierungswünsche_und_Belegungen_konfliktfrei(belegungen, request.RequestData))
            {
                Reservierungswünsche_erfüllen(belegungen, request.RequestData);
                Speichere_Belegungen_zu_Vorstellung(belegungen, request.RequestData.Vorstellung.Termin, request.RequestData.Vorstellung.Saal);
                request.ResponsePin(new Reservierungsbestätigung("<noch keine Reservierungsnummer>", true));
            }
            else
                request.ResponsePin(new Reservierungsbestätigung("", false));
        }


        private void Speichere_Belegungen_zu_Vorstellung(IEnumerable<Belegung> belegungen, DateTime vorstellungstermin, string saal)
        {
            vorstellungstermin = new DateTime(2010, 3, 17, 12, 0, 0);
            saal = "audimax";

            this.repo.Store(belegungen, ErzeugeIdFürVorstellung(vorstellungstermin, saal));
        }


        internal List<Belegung> Finde_Belegungen_zu_Vorstellung(DateTime vorstellungstermin, string saal)
        {
            try
            {
                vorstellungstermin = new DateTime(2010, 3, 17, 12, 0, 0);
                saal = "audimax";

                return repo.Load<List<Belegung>>(ErzeugeIdFürVorstellung(vorstellungstermin, saal));
            }
            catch(EntityStoreException ex)
            {
                if (ex.Message.IndexOf("Error loading") >= 0)
                    return new List<Belegung>();
                throw;
            }
        }



        internal static bool Sind_Reservierungswünsche_und_Belegungen_konfliktfrei(IEnumerable<Belegung> belegungen, Reservierungsanfrage anfrage)
        {
            return belegungen.All(belegung => !anfrage.Reservierungswünsche.Contains(belegung.Platz));
        }


        internal static void Reservierungswünsche_erfüllen(List<Belegung> belegungen, Reservierungsanfrage anfrage)
        {
            belegungen.AddRange(anfrage.Reservierungswünsche.Select(reservierungsplatzwunsch => 
                                    new Belegung("<noch keine R#>", anfrage.Name, anfrage.Email, 
                                                 anfrage.Vorstellung.Termin, anfrage.Vorstellung.Saal, 
                                                 reservierungsplatzwunsch, Belegung.Belegungsstati.Reserviert)));
        }


        internal static string ErzeugeIdFürVorstellung(DateTime vorstellungstermin, string saal)
        {
            return string.Format("{0}@{1}", vorstellungstermin.ToString("yyyyMMdd-hhmmm"), saal);
        }


        public void Dispose()
        {
            this.repo.Dispose();
        }

    }
}
